home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / LIBRARY / TIPS / MODEM.PAS < prev    next >
Pascal/Delphi Source File  |  1991-10-09  |  13KB  |  506 lines

  1. {************************************************}
  2. {                                                }
  3. {   Turbo Pascal for Windows                     }
  4. {   Tips & Techniques Demo Program               }
  5. {   Copyright (c) 1991 by Borland International  }
  6. {                                                }
  7. {************************************************}
  8.  
  9.  
  10. program ModemoDemo;
  11.  
  12. {$R Modem}
  13. uses WinTypes, WinProcs, WObjects, Strings;
  14.  
  15. type
  16.   TEditLine = array[0..50] of Char;
  17.  
  18. const
  19.   idEdit      = 100;
  20.   idDial      = 201;
  21.   idDialStart = 101;
  22.   idPhoneNum  = 102;
  23.   idConfigure = 202;
  24.   id1200      = 101;
  25.   id2400      = 102;
  26.   id4800      = 103;
  27.   id9600      = 104;
  28.   idOdd       = 105;
  29.   idEven      = 106;
  30.   idNone      = 107;
  31.   idComm1     = 108;
  32.   idComm2     = 109;
  33.   id1Stop     = 110;
  34.   id2Stop     = 111;
  35.   id7Data     = 112;
  36.   id8Data     = 113;
  37.  
  38.   LineWidth   = 80;  { Width of each line displayed.                 }
  39.   LineHeight  = 60;  { Number of lines that are held in memory.      }
  40.  
  41.   { The configuration string below is used to configure the modem.  }
  42.   { It is set for communication port 2, 2400 baud, No parity, 8 data }
  43.   { bits, 1 stop bit.                                                }
  44.  
  45.   Comm  : Char = '2';
  46.   Baud  : Word = 24;
  47.   Parity: Char = 'n';
  48.   Stop  : Char = '1';
  49.   Data  : Char = '8';
  50.  
  51.   DialStart: TEditLine = 'ATDT';
  52.   PhoneNumber: TEditLine = '';
  53.  
  54. type
  55.   TApp = object(TApplication)
  56.     procedure Idle; virtual;
  57.     procedure InitMainWindow; virtual;
  58.     procedure MessageLoop; virtual;
  59.   end;
  60.  
  61.   PBuffer = ^TBuffer;
  62.   TBuffer = object(TCollection)
  63.     Pos: Integer;
  64.     constructor Init(AParent: PWindow);
  65.     procedure FreeItem(Item: Pointer); virtual;
  66.     function PutChar(C: Char): Boolean;
  67.   end;
  68.  
  69.   PCommWindow = ^TCommWindow;
  70.   TCommWindow = object(TWindow)
  71.     Cid: Integer;
  72.     Buffer: PBuffer;
  73.     FontRec: TLogFont;
  74.     CharHeight: Integer;
  75.     constructor Init(AParent: PWindowsObject; ATitle: PChar);
  76.     destructor Done; virtual;
  77.     procedure Configure(var Message: TMessage);
  78.       virtual cm_First + idConfigure;
  79.     procedure Dial(var Message: TMessage);
  80.       virtual cm_First + idDial;
  81.     procedure Error(E: Integer; C: PChar);
  82.     procedure Paint(PaintDC: HDC; var PaintInfo: TPaintStruct); virtual;
  83.     procedure ReadChar; virtual;
  84.     procedure SetConfigure;
  85.     procedure SetHeight;
  86.     procedure SetUpWindow; virtual;
  87.     procedure wmChar(var Message: TMessage);
  88.       virtual wm_Char;
  89.     procedure wmSize(var Message: TMessage);
  90.       virtual wm_Size;
  91.     procedure WriteChar;
  92.   end;
  93.  
  94. { TBuffer }
  95. { The Buffer is used to hold each line that is displayed in the main   }
  96. { window.  The constant LineHeight determines the number of lines that }
  97. { are stored.  The Buffer is prefilled with the LineHeight worth of    }
  98. { lines.                                                               }
  99. constructor TBuffer.Init(AParent: PWindow);
  100. var
  101.   P: PChar;
  102.   I: Integer;
  103. begin
  104.   TCollection.Init(LineHeight + 1, 10);
  105.   GetMem(P, LineWidth + 1);
  106.   P[0] := #0;
  107.   Pos := 0;
  108.   Insert(P);
  109.   for I := 1 to LineHeight do
  110.   begin
  111.     GetMem(P, LineWidth + 1);
  112.     P[0] := #0;
  113.     Insert(P);
  114.   end;
  115. end;
  116.  
  117. procedure TBuffer.FreeItem(Item: Pointer);
  118. begin
  119.   FreeMem(Item, LineWidth + 1);
  120. end;
  121.  
  122. { This procedure processes all incoming information from the com     }
  123. { port.  This procedure is called by TCommWindow.ReadChar.           }
  124.  
  125. function TBuffer.PutChar(C: Char): Boolean;
  126. var
  127.   Width: Integer;
  128.   P: PChar;
  129. begin
  130.   PutChar := False;
  131.   Case C of
  132.     #13: Pos := 0;                          { if a Carriage Return.  }
  133.     #10:                                    { if a Line Feed.        }
  134.       begin
  135.         GetMem(P, LineWidth + 1);
  136.         FillChar(P^, LineWidth + 1, ' ');
  137.         P[Pos] := #0;
  138.         Insert(P);
  139.       end;
  140.     #8:
  141.       if Pos > 0 then                       { if a Delete.           }
  142.       begin
  143.         Dec(Pos);
  144.         P := At(Count - 1);
  145.         P[Pos] := ' ';
  146.       end;
  147.    #32..#128:                               { else handle all other  }
  148.     begin                                   { displayable characters.}
  149.       P := At(Count - 1);
  150.       Width := StrLen(P);
  151.       if Width > LineWidth then             { if line is to wide     }
  152.       begin                                 { create a new line.     }
  153.         Pos := 1;
  154.         GetMem(P, LineWidth + 1);
  155.         P[0] := C;
  156.         P[1] := #0;
  157.         Insert(P);
  158.       end
  159.       else                                   { else add character    }
  160.       begin                                  { to current line.      }
  161.         P[Pos] := C;
  162.         Inc(Pos);
  163.         P[Pos] := #0;
  164.       end;
  165.     end;
  166.   end;
  167.   if Count > LineHeight then                 { if too many lines     }
  168.   begin                                      { have been added delete}
  169.     AtFree(0);                               { current line and let  }
  170.     PutChar := True;                         { the call procedure    }
  171.   end;                                       { scroll up.            }
  172. end;
  173.  
  174. { TCommWindow }
  175. { The CommWindow displays the incoming and out going text.              }
  176. { Note that the text typed by the user is displayed by                  }
  177. { being echoed back to the ReadChar procedure.  So there is no need for }
  178. { wmChar to write a character to the screen.                          }
  179. constructor TCommWindow.Init(AParent: PWindowsObject; ATitle: PChar);
  180. begin
  181.   TWindow.Init(AParent, ATitle);
  182.   Attr.Style := Attr.Style or ws_VScroll;
  183.   Attr.Menu := LoadMenu(HInstance, 'Menu_1');
  184.   Scroller := New(PScroller, Init(@Self, 1, 1, 100, 100));
  185.   Buffer := New(PBuffer, Init(@Self));
  186. end;
  187.  
  188. { Close the Comm port and deallocate the Buffer.                      }
  189. destructor TCommWindow.Done;
  190. begin
  191.   Error(CloseComm(Cid), 'Close');
  192.   Dispose(Buffer, Done);
  193.   TWindow.Done;
  194. end;
  195.  
  196. procedure TCommWindow.Configure(var Message: TMessage);
  197. var
  198.   Trans: record
  199.     R1200,
  200.     R2400,
  201.     R4800,
  202.     R9600,
  203.     ROdd,
  204.     REven,
  205.     RNone,
  206.     RComm1,
  207.     RComm2,
  208.     R1Stop,
  209.     R2Stop,
  210.     R7Data,
  211.     R8Data: Word;
  212.   end;
  213.  
  214.   D: TDialog;
  215.   P: PWindowsObject;
  216.   I: Integer;
  217.  
  218. begin
  219.   D.Init(@Self, 'Configure');
  220.   for I := id1200 to id8Data do
  221.     P := New(PRadioButton, InitResource(@D, I));
  222.   with Trans do
  223.   begin
  224.     R1200 := Byte(Baud = 12);
  225.     R2400 := Byte(Baud = 24);
  226.     R4800 := Byte(Baud = 48);
  227.     R9600 := Byte(Baud = 96);
  228.  
  229.     ROdd  := Byte(Parity = 'o');
  230.     REven := Byte(Parity = 'e');
  231.     RNone := Byte(Parity = 'n');
  232.  
  233.     RComm1 := Byte(Comm = '1');
  234.     RComm2 := Byte(Comm = '2');
  235.  
  236.     R1Stop := Byte(Stop = '1');
  237.     R2Stop := Byte(Stop = '2');
  238.  
  239.     R7Data := Byte(Data = '7');
  240.     R8Data := Byte(Data = '8');
  241.   end;
  242.   D.TransferBuffer := @Trans;
  243.   if D.Execute = id_Ok then
  244.   begin
  245.     with Trans do
  246.     begin
  247.       Baud := (R1200 * 12) + (R2400 * 24) + (R4800 * 48) + (R9600 * 96);
  248.       if ROdd = bf_Checked then
  249.         Parity := 'o';
  250.       if REven = bf_Checked then
  251.         Parity := 'e';
  252.       if RNone = bf_Checked then
  253.         Parity := 'n';
  254.       if R1Stop = bf_Checked then
  255.         Stop := '1'
  256.       else
  257.         Stop := '2';
  258.       if RComm1 = bf_Checked then
  259.         Comm := '1'
  260.       else
  261.         Comm := '2';
  262.       if R7Data = bf_Checked then
  263.         Data := '7'
  264.       else
  265.         Data := '8';
  266.       SetConfigure;
  267.     end;
  268.   end;
  269.   D.Done;
  270. end;
  271.  
  272.  
  273. procedure TCommWindow.Dial(var Message: TMessage);
  274. var
  275.   Trans: record
  276.     Start: TEditLine;
  277.     Phone: TEditLine;
  278.   end;
  279.   D: TDialog;
  280.   P: PWindowsObject;
  281. begin
  282.   D.Init(@Self, 'Dial');
  283.   P := New(PEdit, InitResource(@D, idDialStart, SizeOf(TEditLine)));
  284.   P := New(PEdit, InitResource(@D, idPhoneNum, SizeOf(TEditLine)));
  285.   StrCopy(Trans.Start, DialStart);
  286.   StrCopy(Trans.Phone, PhoneNumber);
  287.   D.TransferBuffer := @Trans;
  288.   if D.Execute = id_Ok then
  289.   begin
  290.     StrCopy(DialStart, Trans.Start);
  291.     StrCopy(PhoneNumber, Trans.Phone);
  292.     StrCat(PhoneNumber, #13);
  293.     StrCat(PhoneNumber, #10);
  294.     Error(WriteComm(CId, DialStart, StrLen(DialStart)), 'Writing');
  295.     Error(WriteComm(CId, PhoneNumber, StrLen(PhoneNumber)), 'Writing');
  296.     PhoneNumber[StrLen(PhoneNumber) - 2] := #0;
  297.   end;
  298.   D.Done;
  299. end;
  300.  
  301.  
  302. { Checks for comm errors and writes any errors.                       }
  303. procedure TCommWindow.Error(E: Integer; C: PChar);
  304. var
  305.   S: array[0..100] of Char;
  306. begin
  307.   if E >= 0 then exit;
  308.   Str(E, S);
  309.   MessageBox(GetFocus, S, C, mb_Ok);
  310.   Halt(1);
  311. end;
  312.  
  313. { Redraw all the lines in the buffer using ForEach.                }
  314. procedure TCommWindow.Paint(PaintDC: HDC; var PaintInfo: TPaintStruct);
  315. var
  316.   I: Integer;
  317.   Font: HFont;
  318.  
  319.   procedure WriteOut(Item: PChar); far;
  320.   begin
  321.     TextOut(PaintDC, 0, CharHeight * I, Item, StrLen(Item));
  322.     inc(I);
  323.   end;
  324.  
  325. begin
  326.   I := 0;
  327.   Font := SelectObject(PaintDC, CreateFontIndirect(FontRec));
  328.   Buffer^.ForEach(@WriteOut);
  329.   DeleteObject(SelectObject(PaintDC, Font));
  330. end;
  331.  
  332. { Read a character from the comm port, if there is no error then call }
  333. { Buffer^.PutChar to add it to the buffer and write it to the screen. }
  334. procedure TCommWindow.ReadChar;
  335. var
  336.   Stat: TComStat;
  337.   I, Size: Integer;
  338.   C: Char;
  339. begin
  340.   GetCommError(CID, Stat);
  341.   for I := 1 to Stat.cbInQue do
  342.   begin
  343.     Size := ReadComm(CID, @C, 1);
  344.     Error(Size, 'Read Comm');
  345.     if Size = 0 then Exit;
  346.     if C <> #0 then
  347.     begin
  348.       if Buffer^.PutChar(C) then
  349.       begin
  350.         ScrollWindow(HWindow, 0, -CharHeight, Nil, Nil);
  351.         UpDateWindow(HWindow);
  352.       end;
  353.       WriteChar;
  354.     end;
  355.   end;
  356. end;
  357.  
  358. procedure TCommWindow.SetConfigure;
  359. var
  360.   Config: array[0..20] of Char;
  361.   S: array[0..5] of Char;
  362.   DCB: TDCB;
  363. begin
  364.   StrCopy(Config, 'com?:??,?,?,?');
  365.   Config[3] := Comm;
  366.   Config[8] := Parity;
  367.   Config[10] := Data;
  368.   Config[12] := Stop;
  369.   Str(Baud, S);
  370.   Config[5] := S[0];
  371.   Config[6] := S[1];
  372.   BuildCommDCB(Config, DCB);
  373.   DCB.ID := CID;
  374.   Error(SetCommState(DCB), 'Set Comm State');
  375. end;
  376.  
  377. procedure TCommWindow.SetUpWindow;
  378. var
  379.   DCB: TDCB;
  380.   CommString: array[0..5] of Char;
  381. begin
  382.   TWindow.SetUpWindow;
  383.   SetHeight;
  384.  
  385. { Open for Comm2 2400 Baud, No Parity, 8 Data Bits, 1 Stop Bit }
  386.   StrCopy(CommString, 'Com ');
  387.   CommString[3] := Comm;
  388.   Cid := OpenComm(CommString, 1024, 1024);
  389.   Error(Cid, 'Open');
  390.   SetConfigure;
  391.   WriteComm(Cid, 'ATZ'#13#10, 5);  { Send a reset to Modem. }
  392. end;
  393.  
  394. { Call back function used only to get record structure for fixed   }
  395. { width font.                                                      }
  396. function GetFont(LogFont: PLogFont; TM: PTextMetric; FontType: Word;
  397.   P: PCommWindow): Integer; export;
  398. begin
  399.   if P^.CharHeight = 0 then
  400.   begin
  401.     P^.FontRec := LogFont^;
  402.     P^.CharHeight := P^.FontRec.lfHeight;
  403.   end;
  404. end;
  405.  
  406. { Get a fixed width font to use in the TCommWindow.  Use EnumFonts  }
  407. { to save work of create the FontRec by hand.                         }
  408. { The TScroller of the main window is also updated know that the font }
  409. { height is known.                                                    }
  410. procedure TCommWindow.SetHeight;
  411. var
  412.   DC: HDC;
  413.   ProcInst: Pointer;
  414. begin
  415.   DC := GetDC(HWindow);
  416.   CharHeight := 0;
  417.   ProcInst := MakeProcInstance(@GetFont, HInstance);
  418.   EnumFonts(DC, 'Courier', ProcInst, @Self);
  419.   FreeProcInstance(ProcInst);
  420.   ReleaseDC(HWindow, DC);
  421.  
  422.   Scroller^.SetUnits(CharHeight, CharHeight);
  423.   Scroller^.SetRange(LineWidth, LineHeight);
  424.   Scroller^.ScrollTo(0, LineHeight);
  425. end;
  426.  
  427.  
  428. { Write the character from the pressed key to the Comuniction Port.   }
  429. procedure TCommWindow.wmChar(var Message: TMessage);
  430. begin
  431.   Error(WriteComm(CId, @Message.wParam, 1), 'Writing');
  432. end;
  433.  
  434. procedure TCommWindow.wmSize(var Message: TMessage);
  435. begin
  436.   TWindow.wmSize(Message);
  437.   Scroller^.SetRange(LineWidth, LineHeight - (Message.lParamhi div CharHeight));
  438. end;
  439.  
  440. procedure TCommWindow.WriteChar;
  441. var
  442.   DC: HDC;
  443.   Font: HFont;
  444.   S: PChar;
  445.   APos: Integer;
  446. begin
  447.   APos := Buffer^.Count - 1;
  448.   S := Buffer^.AT(APos);
  449.   APos := (APos - Scroller^.YPos) * CharHeight;
  450.   if APos < 0 then exit;
  451.   if HWindow <> 0 then
  452.   begin
  453.     DC := GetDC(HWindow);
  454.     Font := SelectObject(DC, CreateFontIndirect(FontRec));
  455.     TextOut(DC, 0, APos, S, StrLen(S));
  456.     DeleteObject(SelectObject(DC, Font));
  457.     ReleaseDC(HWindow, DC);
  458.   end;
  459. end;
  460.  
  461. { TApp }
  462. procedure TApp.Idle;
  463. begin
  464.   if MainWindow <> Nil then
  465.     if MainWindow^.HWindow <> 0 then
  466.       PCommWindow(MainWindow)^.ReadChar;
  467. end;
  468.  
  469. procedure TApp.InitMainWindow;
  470. begin
  471.   MainWindow := New(PCommWindow, Init(Nil, 'Comm Test'));
  472. end;
  473.  
  474. { Add Idle loop to main message loop.                                 }
  475. procedure TApp.MessageLoop;
  476. var
  477.   Message: TMsg;
  478. begin
  479.   while True do
  480.   begin
  481.     if PeekMessage(Message, 0, 0, 0, pm_Remove) then
  482.     begin
  483.       if Message.Message = wm_Quit then
  484.       begin
  485.         Status := Message.WParam;
  486.         Exit;
  487.       end;
  488.       if not ProcessAppMsg(Message) then
  489.       begin
  490.         TranslateMessage(Message);
  491.         DispatchMessage(Message);
  492.       end;
  493.     end
  494.     else
  495.       Idle;
  496.   end;
  497. end;
  498.  
  499. var
  500.   App: TApp;
  501. begin
  502.   App.Init('Comm');
  503.   App.Run;
  504.   App.Done;
  505. end.
  506.